/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.srf;

import edu.yonsei.iwb.srf.classifier.CardinalityRestrictionRefinementClassifier;
import com.hp.hpl.jena.vocabulary.RDF;
import edu.yonsei.iwb.di.ESService;
import edu.yonsei.iwb.sdt.datastructure.TargetInstance;
import edu.yonsei.iwb.sdt.datastructure.tree.DEdge;
import edu.yonsei.iwb.sdt.datastructure.tree.DNode;
import edu.yonsei.iwb.sdt.datastructure.tree.NodeType;
import edu.yonsei.iwb.sdt.ontology.PropertyArc;
import edu.yonsei.iwb.sdt.refinement.CardinalityRestrictionRefinement;
import edu.yonsei.iwb.sdt.refinement.ConceptConstructorRefinement;
import edu.yonsei.iwb.sdt.refinement.ConjunctionRefinement;
import edu.yonsei.iwb.sdt.refinement.DLConstructors;
import edu.yonsei.iwb.sdt.refinement.DisjunctionRefinement;
import edu.yonsei.iwb.sdt.refinement.DomainRestrictionRefinement;
import edu.yonsei.iwb.sdt.refinement.ExpandingHistory;
import edu.yonsei.iwb.sdt.refinement.QualificationRefinement;
import edu.yonsei.iwb.sdt.refinement.Refinement;
import edu.yonsei.iwb.sdt.refinement.RefinementType;
import edu.yonsei.iwb.sdt.refinement.ValueInfoOfDP;
import edu.yonsei.iwb.sdt.util.UtilFunctions;
import edu.yonsei.iwb.srf.classifier.ConceptConstructorRefinementClassifier;
import edu.yonsei.iwb.srf.classifier.ConjunctionRefinementClassifier;
import edu.yonsei.iwb.srf.classifier.DisjunctionRefinementClassifier;
import edu.yonsei.iwb.srf.classifier.DomainRestrictionRefinementClassifier;
import edu.yonsei.iwb.srf.classifier.QualificationRefinementClassifier;
import edu.yonsei.iwb.srf.classifier.TestingResultOfTree;
import edu.yonsei.iwb.ts.TSSearch;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;

/**
 *
 * @author dk
 */
public class TestForestDriver {

    private ESService di;
    private TSSearch ts;
    
    private Hashtable<String, Integer> testAnswer;
    private Vector<String> valueList;
    private ArrayList<Integer> mincands;
    private ArrayList<Integer> maxcands;
//    private Hashtable<String, Vector<String>> resultTable;
    private ConceptConstructorRefinementClassifier ccrc;
    private ConjunctionRefinementClassifier crc;
    private DisjunctionRefinementClassifier drc;
    private CardinalityRestrictionRefinementClassifier crrc;
    private QualificationRefinementClassifier qrc;
    private DomainRestrictionRefinementClassifier drrc;
    

    public TestForestDriver(String testIndex) {
//        this.resultTable = new Hashtable();
        
        this.di = new ESService();
        this.ts = new TSSearch(new String[]{testIndex});
        
        this.testAnswer = new Hashtable();
        this.valueList = new Vector();
        this.mincands = new ArrayList();
        this.maxcands = new ArrayList();
        this.ccrc = new ConceptConstructorRefinementClassifier();
        this.crc = new ConjunctionRefinementClassifier();
        this.drc = new DisjunctionRefinementClassifier();

        this.crrc = new CardinalityRestrictionRefinementClassifier();
        this.qrc = new QualificationRefinementClassifier();

        this.drrc = new DomainRestrictionRefinementClassifier();
    }

    public static void main(String[] args) throws ParseException {
        try {
            String runID = "forte2";
            String testDataLoc = "forte1";
            String indexName = "forte";
            
//            String runID = "family1";
//            String testDataLoc = "family1";
//            String indexName = "family2";
            
//            String runID = "family_a10";
//            String testDataLoc = "family_a1";
//            String indexName = "family2";
//            
//            String runID = "media32";
//            String testDataLoc = "media1";            
//            String indexName ="smarttv";
            
            String treeloc = "./trees/master/" + runID;
//            String targetClass = "http://localhost/foo#Person";

            TestForestDriver tfd = new TestForestDriver(indexName);
            Vector<String> insset = tfd.getTestInstanceSet(testDataLoc);
//            for (int i = 0; i < insset.size(); i++) {
//                String string = insset.get(i);
//                System.out.println(" ----- " + string);
//            }
            ArrayList<DNode> trees = tfd.loadTree(treeloc);

            ArrayList<Hashtable<String, Integer>> finalResult = new ArrayList();
            Hashtable<Integer, TestingResultOfTree> tftTable = new Hashtable();

            for (int i = 0; i < trees.size(); i++) {
                DNode tree = trees.get(i);
                
//                UtilFunctions.printNode(tree);
                UtilFunctions.showTree(tree);
                TestingResultOfTree trt = new TestingResultOfTree();
                Hashtable<String, Integer> rt = new Hashtable();
                tfd.classify(tree, insset, trt, rt);
                finalResult.add(rt);
                tftTable.put(i, trt);
            }
//            tfd.printConsole(finalResult);
            tfd.calculateCandNum();
            tfd.printOut(finalResult, runID);
            tfd.finalclass(finalResult, runID);

        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(TestForestDriver.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(TestForestDriver.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(TestForestDriver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void calculateCandNum(){
        
        int min = Integer.MAX_VALUE;
        int max = 0;       
        int sum = 0;
        
//        for (int i = 0; i < this.mincands.size(); i++) {
//            int value = this.mincands.get(i);
//            if(min > value){
//                min = value;
//            }
//            
//            sum += value;
//        }
        
        for (int i = 0; i < this.maxcands.size(); i++) {
            int value = this.maxcands.get(i);
            
            if(min > value){
                min = value;
            }
            
            if(max < value){
                max = value;
            }
            System.out.println("---"+value);
            sum += value;
        }
        
//        int denominator = this.mincands.size() + this.maxcands.size();
        int denominator = this.maxcands.size();
        
        double avg = ((double)sum) / ((double) denominator);
        System.out.println("# Number of candidates");
        System.out.println("  * Min : " + min);
        System.out.println("  * Max : " + max);
        System.out.println("  * Avg : " + longDouble2String(avg));
        
    }

    public void printConsole(ArrayList<Hashtable<String, Integer>> finalResult) {
        for (int i = 0; i < finalResult.size(); i++) {
            System.out.println("# tree number : " + i);
            Hashtable<String, Integer> resultTable = finalResult.get(i);
            Enumeration<String> instances = resultTable.keys();
            while (instances.hasMoreElements()) {
                String uri = instances.nextElement();
                int classify = resultTable.get(uri);
                System.out.println(uri + "\t" + classify);
            }
        }

    }

    private void printOut(ArrayList<Hashtable<String, Integer>> finalResult, String runID) {
        PrintWriter pwtj = null;
        try {
            File dir = new File("./result/" + runID);
            dir.mkdirs();
            
            for (int i = 0; i < finalResult.size(); i++) {
                File rfile = new File("./result/" + runID + "/" + i + "+tree_result.tsv");
                rfile.createNewFile();
                pwtj = new PrintWriter(new OutputStreamWriter(new FileOutputStream(rfile), "euc-kr"));
                Hashtable<String, Integer> resultTable = finalResult.get(i);
                Enumeration<String> instances = resultTable.keys();
                while (instances.hasMoreElements()) {
                    String uri = instances.nextElement();
                    int classify = resultTable.get(uri);
                    pwtj.write(uri + "\t" + classify + "\n");
                }
                pwtj.flush();
                pwtj.close();
            }
        } catch (UnsupportedEncodingException ex) {
            Logger.getLogger(BuildForestDriver.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(BuildForestDriver.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(TestForestDriver.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            pwtj.close();
        }
    }
    
    private void finalclass(ArrayList<Hashtable<String, Integer>> finalResult, String runID) throws IOException{
        Hashtable<String, Hashtable<String,Integer>> cbi = new Hashtable();
        for (int i = 0; i < finalResult.size(); i++) {
            Hashtable<String, Integer> ht = finalResult.get(i);
            Enumeration<String> insset = ht.keys();
            while(insset.hasMoreElements()){
                String ins = insset.nextElement();
                int cv = ht.get(ins);
                String key = this.valueList.get(cv);
                if(cbi.containsKey(ins)){
                    Hashtable<String,Integer> vtable = cbi.get(ins);                    
                    if(vtable.contains(key)){
                        int vsize = vtable.get(key);
                        vsize++;
                        vtable.put(key, vsize);
                    }else{
                        vtable.put(key,1);
                    }                    
                    
                }else{                    
                    Hashtable<String,Integer> vtable = new Hashtable();                    
                    vtable.put(key,1);
                    cbi.put(ins, vtable);
                }
            }            
        }
        
        File rfile = new File("./result/" + runID + "/final_result.tsv");
        rfile.createNewFile();
        PrintWriter pwtj = new PrintWriter(new OutputStreamWriter(new FileOutputStream(rfile), "euc-kr"));
        
        int truesize = 0;
        
        Enumeration<String> tins = this.testAnswer.keys();
        while(tins.hasMoreElements()){
            String ti = tins.nextElement();
            int answer = this.testAnswer.get(ti);
            
            String finalclass = new String();
            int highest = 0;
            Hashtable<String,Integer> vtable = cbi.get(ti);
            
            Enumeration<String> keys = vtable.keys();
            while(keys.hasMoreElements()){
                String key = keys.nextElement();
                int vsize = vtable.get(key);
                if(vsize > highest){
                    highest = vsize;
                    finalclass = key;
                }
            }
//            for (int i = 0; i < this.valueList.size(); i++) {
//                String key = ""+i;
//                System.out.println("++ " + key);
//                int vsize = vtable.get(key);
//                if(vsize > highest){
//                    highest = vsize;
//                    finalclass = i;
//                }                
//            }
            
            if(finalclass.equals(this.valueList.get(answer))){
                pwtj.write(ti+"\t"+finalclass+"\t"+answer+"\tcorrect\n");
                truesize++;
            }else{
                pwtj.write(ti+"\t"+finalclass+"\t"+answer+"\tincorrect\n");
            }                       
        }
        int all = this.testAnswer.keySet().size();
        
                
        double accuracy = ((double)truesize)/((double)all);
        String acc = longDouble2String(accuracy);
        System.out.println("\n# accuracy : " + acc);
        pwtj.write("\n# Final accuracy : " +truesize+"/"+all+" = "+ acc);
        pwtj.flush();
        pwtj.close();
        
    }
    
    private String longDouble2String(double value) {
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMaximumFractionDigits(3);
        nf.setGroupingUsed(false);
        return nf.format(value);
    }

    public ArrayList<DNode> loadTree(String trees) throws UnsupportedEncodingException, FileNotFoundException, IOException {
        File[] treesArray = new File(trees).listFiles();

        ArrayList<DNode> allTrees = new ArrayList();

        for (int i = 0; i < treesArray.length; i++) {
            File treeOfSlave = treesArray[i];
            XContentParser jsonresult = JsonXContent.jsonXContent.createParser(new InputStreamReader(new FileInputStream(treeOfSlave), "euc-kr"));
//            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(treeOfSlave), "euc-kr"));
////            System.out.println("?");
//            String line = null;
//            StringBuilder sb = new StringBuilder();            
//            while ((line = br.readLine()) != null) {
//                System.out.println(line);
//                sb.append(line);
//            }
//            String resultMsg = sb.toString();            
//            allTrees.addAll(interpretResult(resultMsg));
            allTrees.addAll(interpretResult(jsonresult));
        }
        return allTrees;

    }

//    public ArrayList<DNode> loadTree(String trees) throws UnsupportedEncodingException, FileNotFoundException, IOException {
//        File[] treesArray = new File(trees).listFiles();
//        
//        for (int i = 0; i < treesArray.length; i++) {
//            File treeOfSlave = treesArray[i];
//            
//        }
//        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(trees), "euc-kr"));
//        String line = null;
//        StringBuilder sb = new StringBuilder();
//        while ((line = br.readLine()) != null) {
//            sb.append(line);
//        }
//        String resultMsg = sb.toString();
//        return interpretResult(resultMsg);
//    }
    private Hashtable<String, Integer> classify(DNode node, Vector<String> insset, TestingResultOfTree trt, Hashtable<String, Integer> rt) throws IOException, ParseException {

        // 현재는 무조건 binary split 한다는 전제로 개발됨
        
        if (node.getEdge().size() == 1) {
            DEdge edge = node.getEdge().get(0);
            DNode childnode = edge.getChildNode();
            if (edge.getChildNode().NODE_TYPE == NodeType.BRANCHNODE) {
                classify(edge.getChildNode(), insset, trt, rt);
            } else {
                int classlabel = childnode.getFinalClassLabel();
                for (int j = 0; j < insset.size(); j++) {
                    String ins = insset.get(j);
                    rt.put(ins, classlabel);
                }
            }
        } else {
            for (int i = 0; i < node.getEdge().size(); i++) {
                DEdge edge = node.getEdge().get(i);

                Vector<String> stopset = null;
                if (edge.getEdgeType()) {
//                    System.out.print("# satis branch");
//                    System.out.print(edge.toString());
                    stopset = this.classifyByRefinement(edge, insset);
//                    System.out.println(stopset);


                    Vector<String> unsatisset = new Vector();
                    for (int j = 0; j < insset.size(); j++) {
                        String ins = insset.get(j);
                        if (!stopset.contains(ins)) {
                            unsatisset.add(ins);
                        }
                    }

                    trt.putSatisfiedSet(edge.getChildNode().NODE_ID, stopset);
                    trt.putUnsatisfiedSet(edge.getParentNode().NODE_ID, unsatisset);
                } else {
//                    System.out.print("# unsatis branch");
//                    System.out.print(edge.toString());
                    if (trt.unSatisfiedContains(edge.getParentNode().NODE_ID)) {
//                        System.out.println("  -  adding already exist unsatisfired set");
                        stopset = trt.getUnsatisfiedSet(edge.getParentNode().NODE_ID);
                    } else {
//                        System.out.println("  -  other case");
                        Vector<String> satisset = this.classifyByRefinement(edge, insset);
                        Vector<String> unsatisset = new Vector();
                        for (int j = 0; j < insset.size(); j++) {
                            String ins = insset.get(j);
                            if (!satisset.contains(ins)) {
                                unsatisset.add(ins);
                            }
                        }
                        trt.putSatisfiedSet(edge.getChildNode().NODE_ID, satisset);
                        trt.putUnsatisfiedSet(edge.getParentNode().NODE_ID, unsatisset);
                        stopset = unsatisset;
                    }
                }

                DNode childnode = edge.getChildNode();
                if (edge.getChildNode().NODE_TYPE == NodeType.BRANCHNODE) {
//                    System.out.println("  -  this is branch node\n");
//                    System.out.println(" ---- " + stopset.size());
                    classify(edge.getChildNode(), stopset, trt, rt);
                } else {
//                    System.out.println("  -  this is leaf node");
                    int classlabel = childnode.getFinalClassLabel();
//                    System.out.println("  ++++++  " + classlabel);
                    for (int j = 0; j < stopset.size(); j++) {
                        String ins = stopset.get(j);
                        rt.put(ins, classlabel);
                    }
                }
            }
        }

        return rt;
    }

    private Vector<String> classifyByRefinement(DEdge edge, Vector<String> insset) throws IOException, ParseException {

        Refinement ref = edge.getRefinement();
        int reftype = ref.getRefinementType();
        if (reftype == RefinementType.CARDINALITYRESTRICTION) {
            PropertyArc pa = ((CardinalityRestrictionRefinement) ref).getConditionp();
            int standard = ((CardinalityRestrictionRefinement) ref).getStandard();
            Vector<String> instances = new Vector(insset);
            ExpandingHistory eh = ref.getExpandingHistory();
            if (eh == null) {
                return this.crrc.satisfiedSet(instances, pa, standard);
            } else {
                Vector<PropertyArc> pset = eh.getPropertySet();
                Vector<String> qset = eh.getQuantifierSet();
                return this.crrc.satisfiedSet(instances, pa, standard, pset, qset);
            }
        } else if (reftype == RefinementType.QUALIFICATION) {
            String classname = ((QualificationRefinement) ref).getConditionResource();
            ExpandingHistory eh = ref.getExpandingHistory();
            Vector<PropertyArc> pset = eh.getPropertySet();
            Vector<String> qset = eh.getQuantifierSet();
            return this.qrc.satisfiedSet(classname, insset, pset, qset);
        } else if (reftype == RefinementType.CONCEPTCONSTRUCTOR) {
//            System.out.println("  -  classify by concept constructor refinement");
            String classname = ((ConceptConstructorRefinement) ref).getConditionResource();
            return this.ccrc.satisfiedSet(insset, classname);
        } else if (reftype == RefinementType.CONJUNCTION) {
            String cenclass = ((ConjunctionRefinement) ref).getConditionr();
            String conclass = ((ConjunctionRefinement) ref).getMateConditionr();
            ExpandingHistory eh = ref.getExpandingHistory();
            if (eh == null) {
                return this.crc.satisfiedSet(insset, cenclass, conclass);
            } else {
                Vector<PropertyArc> pset = eh.getPropertySet();
                Vector<String> qset = eh.getQuantifierSet();
                return this.crc.satisfiedSet(insset, cenclass, conclass, pset, qset);
            }
        } else if (reftype == RefinementType.DISJUNCTION) {
            String cenclass = ((DisjunctionRefinement) ref).getConditionr();
            String conclass = ((DisjunctionRefinement) ref).getMateConditionr();
            Refinement typedref = ((DisjunctionRefinement) ref);
            ExpandingHistory eh = typedref.getExpandingHistory();
            if (eh == null) {
                return this.drc.satisfiedSet(insset, cenclass, conclass);
            } else {
                Vector<PropertyArc> pset = eh.getPropertySet();
                Vector<String> qset = eh.getQuantifierSet();
                return this.drc.satisfiedSet(insset, cenclass, conclass, pset, qset);
            }
        } else {
            int dtype = ((DomainRestrictionRefinement) ref).getViotype();
            String standard = ((DomainRestrictionRefinement) ref).getStandard();
            String property = ((DomainRestrictionRefinement) ref).getProperty();

            ExpandingHistory eh = ref.getExpandingHistory();
            if (eh == null) {
                return this.drrc.satisfiedSet(dtype, property, standard, insset);
            } else {
                Vector<PropertyArc> pset = eh.getPropertySet();
                Vector<String> qset = eh.getQuantifierSet();
                return this.drrc.satisfiedSet(dtype, property, standard, insset, pset, qset);
            }
        }
    }

    private Vector<String> getTestInstanceSet(String dir) throws IOException {
        File vlist = new File("./dataset/" + dir + "/vlist.tsv");
        BufferedReader br2 = new BufferedReader(new InputStreamReader(new FileInputStream(vlist), "euc-kr"));
        String line2 = null;
        while ((line2 = br2.readLine()) != null) {
            String[] s = line2.split("\t");
            String su = s[0];
            int value = Integer.parseInt(s[1]);
            this.valueList.add(value, su);
        }        
        
        Vector<String> tiset = new Vector();        
        File testf = new File("./dataset/" + dir + "/test.tsv");
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(testf), "euc-kr"));
        String line = null;        
        while ((line = br.readLine()) != null) {
            String[] s = line.split("\t");
            System.out.println("---"+line);
            tiset.add(s[0]);   
            this.testAnswer.put(s[0], this.valueList.indexOf(s[1]));
        }        
        return tiset;
    }

//    private Vector<String> getTestInstanceSet(String targetclassname) throws IOException {
//        ArrayList<String> tisetarray = TSSearch.listSubjectResource(RDF.type.getURI(), targetclassname);
//        Vector<String> tiset = new Vector(tisetarray);
//        return tiset;
//    }

    private ArrayList<DNode> interpretResult( XContentParser jsonResult) throws IOException {
//    private ArrayList<DNode> interpretResult(String result) throws IOException {
        ArrayList<DNode> resultTreeSet = new ArrayList();

//        XContentParser jsonResult = JsonXContent.jsonXContent.createParser(result);
        Map<String, Object> resultMap = jsonResult.mapOrdered();
        Map<String, Object> set = (Map<String, Object>) resultMap.get("set");
        String slavenum = set.get("slavenum").toString();
        String treeSize = set.get("size").toString();

        System.out.println("# treesize : " + treeSize);
        System.out.println("# slavenum : " + slavenum);

        for (int j = 0; j < Integer.parseInt(treeSize); j++) {
            LinkedHashMap treeinfo = (LinkedHashMap) set.get("id" + slavenum + "_" + j);
            String rootid = treeinfo.get("rootid").toString();            
            ArrayList candnums = (ArrayList) treeinfo.get("candnum");     
//            System.out.println(" **************  " + candnums.get(0));
//            System.out.println(" **************  " + candnums.get(1));
            this.mincands.add((Integer) candnums.get(0));
            this.maxcands.add((Integer) candnums.get(1));
            
            Hashtable<String, DNode> nodeTable = new Hashtable();
            ArrayList<String> nodelist = (ArrayList<String>) treeinfo.get("nodelist");
            for (int i = 0; i < nodelist.size(); i++) {
                String nodeIDinJSON = nodelist.get(i);
                LinkedHashMap node = (LinkedHashMap) treeinfo.get(nodeIDinJSON);
                String nodeid = node.get("nodeid").toString();
                double entropy = (double) node.get("entropy");
                String noderef = node.get("noderef").toString();

//                ArrayList<String> tiIDs = (ArrayList<String>) node.get("tiIDs");
//                ArrayList<String> tiURIs = (ArrayList<String>) node.get("tiURIs");
//                ArrayList<Integer> tiValues = (ArrayList<Integer>) node.get("tiValues");
//                Vector<TargetInstance> nodeTIset = new Vector();
//
//                for (int k = 0; k < tiIDs.size(); k++) {
//                    String id = tiIDs.get(k);
//                    String uri = tiURIs.get(k);
//                    int value = tiValues.get(k);
//                    TargetInstance ti = new TargetInstance(id, uri, value);
//                    nodeTIset.add(ti);
//                }

//                DNode dn = new DNode(nodeTIset, noderef, Integer.parseInt(nodeid), entropy);
                DNode dn = new DNode(noderef, Integer.parseInt(nodeid), entropy);
                dn.NODE_TYPE = (int) node.get("nodetype");
                if (dn.NODE_TYPE == NodeType.LEAFNODE) {
                    int classLabel = (int) node.get("nodeclass");
                    dn.setFinalClassLabel(classLabel);
                }
                dn.setTargetValueInstanceInformation();
                nodeTable.put(nodeIDinJSON, dn);
            }

            for (int i = 0; i < nodelist.size(); i++) {
                String nodeid = nodelist.get(i);
                LinkedHashMap node = (LinkedHashMap) treeinfo.get(nodeid);
                int cnsize = (int) node.get("cnsize");
                //child node 정보로 edge 생성...
                for (int k = 0; k < cnsize; k++) {
                    String childID = "child_" + k;
                    LinkedHashMap childNodeInfo = (LinkedHashMap) node.get(childID);
                    int cnid = (int) childNodeInfo.get("cnid");
                    boolean branchType = (boolean) childNodeInfo.get("edgetype");
                    String refname = (String) childNodeInfo.get("refname");

                    Refinement ref = getRefinementInfo(childNodeInfo, branchType);
                    ref.setBranchingType(branchType);
                    ref.setRefinementname(refname);

                    DNode parentNode = nodeTable.get(nodeid);
                    DNode childNode = nodeTable.get("n_" + cnid);
                    DEdge de = new DEdge(parentNode, childNode, ref);
                    parentNode.setEdge(de);
                }
            }

            resultTreeSet.add(nodeTable.get("n_" + rootid));
        }
        return resultTreeSet;
    }

    private Refinement getRefinementInfo(LinkedHashMap childNodeInfo, boolean branchType) {
        int type = (int) childNodeInfo.get("reftype");
        boolean expanded = (boolean) childNodeInfo.get("expanded");
        Refinement ref = null;
        ExpandingHistory eh;
        if (expanded) {
            Vector<String> qset = new Vector((ArrayList<String>) childNodeInfo.get("qset"));
            Vector<PropertyArc> paset = new Vector();
            ArrayList<String> pset = (ArrayList<String>) childNodeInfo.get("pset");
            ArrayList<Boolean> pdset = (ArrayList<Boolean>) childNodeInfo.get("pdset");
            for (int l = 0; l < pdset.size(); l++) {
                String property = pset.get(l);
                boolean direction = pdset.get(l);
                paset.add(new PropertyArc(property, direction));
            }
            eh = new ExpandingHistory(paset, qset);

            if (type == RefinementType.CONJUNCTION) {
                String cen = childNodeInfo.get("cen").toString();
                String con = childNodeInfo.get("con").toString();
                if (branchType) {
                    ref = new ConjunctionRefinement("", eh, cen, con);
                } else {
                    ref = new ConjunctionRefinement(DLConstructors.NEGATION, eh, cen, con);
                    ref.setBranchingType(branchType);
                }
            } else if (type == RefinementType.DISJUNCTION) {
                String cen = childNodeInfo.get("cen").toString();
                String con = childNodeInfo.get("con").toString();
                if (branchType) {
                    ref = new DisjunctionRefinement("", eh, cen, con);
                } else {
                    ref = new DisjunctionRefinement(DLConstructors.NEGATION, eh, cen, con);
                    ref.setBranchingType(branchType);
                }
            } else {
                if (type == RefinementType.CARDINALITYRESTRICTION) {
                    String property = childNodeInfo.get("property").toString();
                    boolean pdir = (boolean) childNodeInfo.get("pdir");
                    PropertyArc pa = new PropertyArc(property, pdir);
                    int standard = (int) childNodeInfo.get("standard");
                    if (branchType) {
                        ref = new CardinalityRestrictionRefinement(standard, ">", pa, eh);
                    } else {
                        ref = new CardinalityRestrictionRefinement(standard, "<=", pa, eh);
                    }
                } else if (type == RefinementType.QUALIFICATION) {
                    String cen = childNodeInfo.get("cen").toString();
                    if (branchType) {
                        ref = new QualificationRefinement("", eh, cen);
                    } else {
                        ref = new QualificationRefinement(DLConstructors.NEGATION, eh, cen);
                    }
                } else if (type == RefinementType.DOMAINRESTRICTION) {
                    int dtype = (int) childNodeInfo.get("dtype");
                    String property = childNodeInfo.get("property").toString();
                    if (dtype == ValueInfoOfDP.DATARANGE) {
                        if (branchType) {
                            String standard = childNodeInfo.get("standard").toString();
                            ref = new DomainRestrictionRefinement(standard, "==", eh, property, dtype);
                        } else {
                            Vector<String> datarange = (Vector<String>) childNodeInfo.get("datarange");
                            ref = new DomainRestrictionRefinement(datarange, eh, property);
                        }
                    } else {
                        String prefix = childNodeInfo.get("prefix").toString();
                        String standard = childNodeInfo.get("standard").toString();
                        ref = new DomainRestrictionRefinement(standard, prefix, eh, property, dtype);
                    }
                }

            }
        } else {
            // not expanded
            if (type == RefinementType.CONCEPTCONSTRUCTOR) {
                if (branchType) {
                    boolean multi = (boolean) childNodeInfo.get("multi");
                    if (multi) {
                        ArrayList<String> subset = (ArrayList<String>) childNodeInfo.get("subset");
                        ref = new ConceptConstructorRefinement(subset);
                    } else {
                        String con = childNodeInfo.get("con").toString();
                        ref = new ConceptConstructorRefinement(DLConstructors.NEGATION, con);
                    }
                } else {
                    String con = childNodeInfo.get("con").toString();
                    ref = new ConceptConstructorRefinement("", con);
                }
            } else if (type == RefinementType.CONJUNCTION) {
                String cen = childNodeInfo.get("cen").toString();
                String con = childNodeInfo.get("con").toString();
                if (branchType) {
                    ref = new ConjunctionRefinement("", cen, con);
                } else {
                    ref = new ConjunctionRefinement(DLConstructors.NEGATION, cen, con);
                }
            } else if (type == RefinementType.DISJUNCTION) {
                String cen = childNodeInfo.get("cen").toString();
                String con = childNodeInfo.get("con").toString();
                if (branchType) {
                    ref = new DisjunctionRefinement("", cen, con);
                } else {
                    ref = new DisjunctionRefinement(DLConstructors.NEGATION, cen, con);
                }
            } else {
                if (type == RefinementType.CARDINALITYRESTRICTION) {
                    String property = childNodeInfo.get("property").toString();
                    boolean pdir = (boolean) childNodeInfo.get("pdir");
                    PropertyArc pa = new PropertyArc(property, pdir);
                    int standard = (int) childNodeInfo.get("standard");
                    if (branchType) {
                        ref = new CardinalityRestrictionRefinement(standard, ">", pa);
                    } else {
                        ref = new CardinalityRestrictionRefinement(standard, "<=", pa);
                    }
                } else if (type == RefinementType.DOMAINRESTRICTION) {
                    int dtype = (int) childNodeInfo.get("dtype");
                    String property = childNodeInfo.get("property").toString();
                    if (dtype == ValueInfoOfDP.DATARANGE) {
                        if (branchType) {
                            String standard = childNodeInfo.get("standard").toString();
                            ref = new DomainRestrictionRefinement(standard, "==", property, dtype);
                        } else {
                            Vector<String> datarange = (Vector<String>) childNodeInfo.get("datarange");
                            ref = new DomainRestrictionRefinement(datarange, property);
                        }
                    } else {
                        String prefix = childNodeInfo.get("prefix").toString();
                        String standard = childNodeInfo.get("standard").toString();
                        ref = new DomainRestrictionRefinement(standard, prefix, property, dtype);
                    }
                }
            }
        }
        return ref;
    }
}
